tmpfs panic fix - was Re: udp packet storms - ping death

[8LGM] Security Team (8lgm@bagpuss.demon.co.uk)
Sat, 5 Nov 1994 21:04:49 +0000 (GMT)

David A. Wagner wrote:
>
> ObBug: if you use the SunOS tmpfs, try
> 
> cd /tmp; /usr/etc/mknod fifo p; ln fifo link; ls -ClFg link fifo
>
> ...but not at peak hours!
>
> Sun knows about it and after a year, there's still no fix.  [As
> far as I know -- if there's one, I'd love to hear of it, so I can
> tell the computer center here to add the darn thing: after hearing
> of this one, they hacked the kernel and removed the mkfifo and
> mknod S_IFIFO system calls. <sigh>]

Here is our workaround for this.  The problem is that for a special file,
tmp_link() tries to update the link count (va_nlink in vattr) in the snode's
vnode, rather than the real vnode.

We take no responsibility for this code; it was developed without any source.
Read it through and then use it if you like it.  It works for us on SunOS 4.1.1
on a Sun3.  Not tested on anything else.

If you do use it, we'd be interested to hear whether or not it works for you.
Please mail 8lgm@bagpuss.demon.co.uk.

To use this, create the following program - 8lgm_tmpfs.c.  Then compile and
load using the commands described in the header comment.

8<------------------------- cut here -------------------------

/*
 * 8lgm_tmpfs.c -  SunOS 4.1.x TMPFS bugfix.
 * Copyright (C) 1994 by [8LGM].
 *
 * This works around a fatal bug in tmpfs, reported to Bugtraq
 * by dawagner@phoenix.princeton.edu (David A. Wagner) on 2/11/94.
 *
 * Bug:
 *	cd /tmp; /usr/etc/mknod fifo p; ln fifo link; ls -ClFg link fifo
 * 	panics the kernel with a bus error.
 *
 * To use:
 * 	cc -c -O -DKERNEL -D<kernel-arch> 8lgm_tmpfs.c
 * 	modload 8lgm_tmpfs.o
 */

#include <sys/types.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/user.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/ucred.h>
#include <sys/syslog.h>
#include <sundev/mbvar.h>
#include <sun/autoconf.h>
#include <sun/vddrv.h>

extern	struct vnodeops tmp_vnodeops;
struct	vdldrv vd;

int	(*real_tmp_link)();
int	loaded_8lgm = 0;

int
tmp_link_8lgm(vn, dirp, name, cred)
	struct vnode *vn;
	struct vnode *dirp;
	char *name;
	struct ucred*cred;
{
	struct vnode *real_vn;
	
	if (!(VOP_REALVP(vn, &real_vn)))
		vn = real_vn;
	return ((real_tmp_link)(vn, dirp, name, cred));
}


int
load_8lgm_tmpfsfix()
{
	int	x;

	x = splhigh();
	real_tmp_link = tmp_vnodeops.vn_link;
	tmp_vnodeops.vn_link = tmp_link_8lgm;
	splx(x);
	return(0);
}


int
unload_8lgm_tmpfsfix()
{
	int	x;

	x = splhigh();
	tmp_vnodeops.vn_link = real_tmp_link;
	splx(x);
	return(0);
}


int
xxxinit(function_code, vdp, vdi, vds)
	unsigned int function_code;
	struct vddrv *vdp;
	addr_t vdi;
	struct vdstat *vds;
{
	bzero(&vd, sizeof(vd));
	vd.Drv_magic = VDMAGIC_PSEUDO;
	vd.Drv_name = "8lgm-tmpfs";

	switch(function_code) {
		case VDLOAD:
			if (loaded_8lgm) {
				log(LOG_INFO, "8lgm: tmpfs fix module loaded\n");
				return(EEXIST);
			}
			vdp->vdd_vdtab = (struct vdlinkage*)&vd;
			load_8lgm_tmpfsfix();
			loaded_8lgm++;
			log(LOG_INFO, "8lgm: tmpfs fix module loaded\n");
			return(0);
		case VDUNLOAD:
			return (unload(vdp, vdi));
		case VDSTAT:
			return(0);
		default:
			return(EIO);
	}
}


static int
unload(vdp, vdi)
	struct vddrv *vdp;
	struct vdioctl_unload *vdi;
{
	if (loaded_8lgm == 0) {
		log(LOG_INFO, "8lgm: tmpfs fix module not loaded!\n");
		return(0);
	}
	unload_8lgm_tmpfsfix();
	loaded_8lgm = 0;
	log(LOG_INFO, "8lgm: tmpfs fix module unloaded\n");
	return(0);
}

8<------------------------- cut here -------------------------

-----------------------------------------------------------------------
$ echo help | mail 8lgm-fileserver@bagpuss.demon.co.uk  (Fileserver help)
8lgm-bugs@bagpuss.demon.co.uk           (To report security flaws)
8lgm-request@bagpuss.demon.co.uk        (Request to be added to list)
8lgm@bagpuss.demon.co.uk                (General enquiries)